Wasserbau 4 – Übung 02

Wasserbau 4 – Übung 02#

Aufgabe 1 – Interaktiver Wehrbedienungsplan#

Dieses interaktive Notebook erlaubt es, Parameter für eine Wehranlage selbst zu variieren und die Auswirkungen auf hydraulische Kenngrößen zu untersuchen.

# Konstanten
b_klappe = 7.2  # Breite pro Klappe [m]
g = 9.81        # Erdbeschleunigung [m/s²]
import ipywidgets as widgets
from ipywidgets import interact
from IPython.display import display

# Interaktive Eingabe der Parameter
mu_widget = widgets.FloatSlider(value=0.65, min=0.4, max=1.0, step=0.01, description='μ:')
n_widget = widgets.IntSlider(value=4, min=1, max=5, step=1, description='Klappen n:')
Q_widget = widgets.FloatSlider(value=440, min=10, max=500, step=10, description='Q [m³/s]:')
h1_widget = widgets.FloatSlider(value=1.19, min=1.0, max=2.0, step=0.005, description='h1 [m]:')

#display(mu_widget, n_widget, Q_widget, h1_widget)

def berechne_interaktiv(mu, n, Q, h1):
    A = b_klappe * n
    v1 = Q / (A * h1)
    Fr = v1 / (g * h1)**0.5
    h2_erf = (h1 / 2) * ((8 * Fr**2 + 1)**0.5 - 1)
    print(f"Froude-Zahl Fr = {Fr:.2f}")
    print(f"Erforderliche Tiefe h2_erf = {h2_erf:.2f} m")
    
interact(berechne_interaktiv, mu=mu_widget, n=n_widget, Q=Q_widget, h1=h1_widget)
<function __main__.berechne_interaktiv(mu, n, Q, h1)>
import pandas as pd
import plotly.express as px
import ipywidgets as widgets
from IPython.display import display

# Gegebene Daten für h2_erf und Abfluss bei verschiedenen Klappenanzahlen
data = {
    "h2_erf [m]": [1.49, 2.67, 4.09, 5.76],
    "n=1": [6, 20, 50, 110],
    "n=2": [12, 40, 100, 220],
    "n=3": [18, 60, 150, 330],
    "n=4": [24, 80, 200, 440],
    "n=5": [30, 100, 250, 550],
}

# Erstellen eines Pandas DataFrames aus dem Dictionary
df = pd.DataFrame(data)

# Funktion zum Anzeigen des Diagramms
def zeige_diagramm():
    # Erstellen einer Liste aller Spalten für die Klappenanzahlen
    spalten = [f"n={n}" for n in range(1, 6)]

    # Erstellen des Diagramms mit Plotly Express
    fig = px.line(df, y="h2_erf [m]", x=spalten,
                  title="Wehrbedienungsplan (Alle Klappen)",
                  labels={"h2_erf [m]": "h2_erf [m]", "value": "Abfluss Q [m³/s]", "variable": "Klappenanzahl"},
                  markers=True,
                  range_x=[0, 550],
                  range_y=[0, 6])

    # Anpassen des Layouts des Diagramms
    fig.update_layout(
        yaxis_title="h2_erf [m]",
        xaxis_title="Abfluss Q [m³/s]",
        yaxis_range=[0, 6],
        xaxis_range=[0, 550],
        yaxis_gridcolor='lightgrey',
        xaxis_gridcolor='lightgrey',
        plot_bgcolor='white'
    )

    # Anzeigen des Diagramms
    fig.show()

# Anzeigen des Diagramms (ohne interaktives Widget)
zeige_diagramm()

Plotly-Diagramme sind ein wertvolles Werkzeug, um hydraulische Daten interaktiv zu erkunden. Anders als statische Grafiken ermöglichen sie es, durch einfaches Hovern mit der Maus präzise Werte an einzelnen Datenpunkten abzulesen. Für Detailanalysen könnt ihr in bestimmte Bereiche zoomen oder das Diagramm verschieben. Ein wesentliches Feature ist die interaktive Legende: Einzelne Datensätze lassen sich durch einen Klick gezielt ein- oder ausblenden. Der Doppelklick auf einen Eintrag in der Legende isoliert diesen Datensatz, was den Vergleich mit anderen Datensätzen vereinfacht.

✍ Aufgabe:#

Variieren Sie den Abfluss Q und beobachten Sie, wie sich die erforderliche Wassertiefe h2_erf verändert.

Was passiert bei hoher Froude-Zahl?

Wie verändert sich der Wehrbedienungsplan bei geringer Klappenzahl?

import pandas as pd
import plotly.express as px
import dash
from dash import dcc, html, Input, Output

# Daten definieren
abflusskurve_data = {
    "Q": [0, 20, 24, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 320, 340, 360, 380, 400, 420, 440],
    "hu": [0, 0.6, 0.66, 0.9, 1.15, 1.37, 1.59, 1.78, 1.97, 2.13, 2.3, 2.45, 2.6, 2.75, 2.89, 3.02, 3.15, 3.28, 3.4, 3.52, 3.64, 3.76, 3.82, 3.9]
}

df_abflusskurve = pd.DataFrame(abflusskurve_data)
rp = [(24, 0.66), (80, 1.37), (200, 2.45), (440, 3.9)]

toleranz_Q = 10
toleranz_hu = 0.1

# Dash-App erstellen
app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Graph(id='abfluss-plot', config={'displayModeBar': False}),
    html.Div(id='rueckmeldung', style={'font-weight': 'bold', 'font-size': '18px', 'margin-top': '10px'}),
    html.Div(id='korrekte-punkte', style={'margin-top': '10px'}),
    html.Div(id='erfolg-nachricht', style={'font-weight': 'bold', 'font-size': '20px', 'color': 'green', 'margin-top': '20px'})
])

korrekt_ausgewaehlt = []

@app.callback(
    [Output('abfluss-plot', 'figure'), 
     Output('rueckmeldung', 'children'),
     Output('korrekte-punkte', 'children'),
     Output('erfolg-nachricht', 'children')],
    Input('abfluss-plot', 'clickData')
)
def update_plot(clickData):
    global korrekt_ausgewaehlt
    
    fig = px.line(df_abflusskurve, x='Q', y='hu', title="Finde die richtigen Punkte!",
                  labels={'Q': 'Abfluss Q [m³/s]', 'hu': 'hu [m]'}, line_shape='linear')
    fig.update_traces(line=dict(color='blue'))
    
    rueckmeldung = "Klicke auf einen Punkt in der Grafik."
    erfolg_nachricht = ""
    
    if clickData:
        clicked_x = clickData['points'][0]['x']
        clicked_y = clickData['points'][0]['y']
        
        richtig = any(abs(clicked_x - Q) <= toleranz_Q and abs(clicked_y - hu) <= toleranz_hu for Q, hu in rp)
        
        if richtig:
            naechster_punkt = next((p for p in rp if abs(clicked_x - p[0]) <= toleranz_Q and abs(clicked_y - p[1]) <= toleranz_hu), None)
            if naechster_punkt and naechster_punkt not in korrekt_ausgewaehlt:
                farbe = 'green'
                rueckmeldung = "✅ Punkt richtig!"
                korrekt_ausgewaehlt.append(naechster_punkt)
                if len(korrekt_ausgewaehlt) == len(rp):
                    erfolg_nachricht = "Herzlichen Glückwunsch - alle Punkte gefunden!"
            else:
                farbe = 'orange'
                rueckmeldung = "Dieser Punkt wurde bereits ausgewählt."
        else:
            farbe = 'red'
            rueckmeldung = "❌ Punkt falsch!"
        
        fig.add_scatter(x=[clicked_x], y=[clicked_y], mode='markers', marker=dict(size=12, color=farbe))
    
    # Füge alle korrekt ausgewählten Punkte hinzu
    for x, y in korrekt_ausgewaehlt:
        fig.add_scatter(x=[x], y=[y], mode='markers', marker=dict(size=12, color='green'))
    
    korrekte_punkte_text = [
        html.Div([
            html.Span("h_u,", style={'font-size': '18px'}),
            html.Span(f"{int(x)}", style={'font-size': '14px', 'vertical-align': 'sub'}),
            html.Span(f" = {y:.2f}", style={'font-size': '18px'})
        ]) for x, y in korrekt_ausgewaehlt
    ]
    
    return fig, rueckmeldung, korrekte_punkte_text if korrekte_punkte_text else "", erfolg_nachricht

if __name__ == '__main__':
    app.run(debug=False)
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
Cell In[4], line 85
     82     return fig, rueckmeldung, korrekte_punkte_text if korrekte_punkte_text else "", erfolg_nachricht
     84 if __name__ == '__main__':
---> 85     app.run(debug=False)

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\dash\dash.py:2257, in Dash.run(self, host, port, proxy, debug, jupyter_mode, jupyter_width, jupyter_height, jupyter_server_url, dev_tools_ui, dev_tools_props_check, dev_tools_serve_dev_bundles, dev_tools_hot_reload, dev_tools_hot_reload_interval, dev_tools_hot_reload_watch_interval, dev_tools_hot_reload_max_retry, dev_tools_silence_routes_logging, dev_tools_disable_version_check, dev_tools_prune_errors, **flask_run_options)
   2254             extra_files.append(path)
   2256 if jupyter_dash.active:
-> 2257     jupyter_dash.run_app(
   2258         self,
   2259         mode=jupyter_mode,
   2260         width=jupyter_width,
   2261         height=jupyter_height,
   2262         host=host,
   2263         port=port,
   2264         server_url=jupyter_server_url,
   2265     )
   2266 else:
   2267     self.server.run(host=host, port=port, debug=debug, **flask_run_options)

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\dash\_jupyter.py:405, in JupyterDash.run_app(self, app, mode, width, height, host, port, server_url)
    403     display(HTML(msg))
    404 else:
--> 405     raise final_error

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\dash\_jupyter.py:392, in JupyterDash.run_app(self, app, mode, width, height, host, port, server_url)
    389         raise err
    391 try:
--> 392     wait_for_app()
    394     if self.in_colab:
    395         JupyterDash._display_in_colab(dashboard_url, port, mode, width, height)

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\retrying.py:56, in retry.<locals>.wrap.<locals>.wrapped_f(*args, **kw)
     54 @six.wraps(f)
     55 def wrapped_f(*args, **kw):
---> 56     return Retrying(*dargs, **dkw).call(f, *args, **kw)

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\retrying.py:266, in Retrying.call(self, fn, *args, **kwargs)
    263 if self.stop(attempt_number, delay_since_first_attempt_ms):
    264     if not self._wrap_exception and attempt.has_exception:
    265         # get() on an attempt with an exception should cause it to be raised, but raise just in case
--> 266         raise attempt.get()
    267     else:
    268         raise RetryError(attempt)

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\retrying.py:301, in Attempt.get(self, wrap_exception)
    299         raise RetryError(self)
    300     else:
--> 301         six.reraise(self.value[0], self.value[1], self.value[2])
    302 else:
    303     return self.value

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\six.py:724, in reraise(tp, value, tb)
    722     if value.__traceback__ is not tb:
    723         raise value.with_traceback(tb)
--> 724     raise value
    725 finally:
    726     value = None

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\retrying.py:251, in Retrying.call(self, fn, *args, **kwargs)
    248     self._before_attempts(attempt_number)
    250 try:
--> 251     attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
    252 except:
    253     tb = sys.exc_info()

File ~\anaconda3\envs\hausarbeit_wb4\lib\site-packages\dash\_jupyter.py:383, in JupyterDash.run_app.<locals>.wait_for_app()
    381     if res != "Alive":
    382         url = f"http://{host}:{port}"
--> 383         raise OSError(
    384             f"Address '{url}' already in use.\n"
    385             "    Try passing a different port to run."
    386         )
    387 except requests.ConnectionError as err:
    388     _get_error()

OSError: Address 'http://127.0.0.1:8050' already in use.
    Try passing a different port to run.
import dash
from dash import dcc, html, Input, Output, State, dash_table
import pandas as pd
import math

# Dash-App erstellen
app = dash.Dash(__name__)

# Formel zur Berechnung von Q
def berechne_Q(hu, n):
    µ = 0.65
    b = n * 7.2
    g = 9.81
    return (2 / 3) * µ * b * math.sqrt(2 * g) * (hu ** (3 / 2))

# Daten definieren
hü_values = [0, 1, 2, 3, 4]
n_values = [1, 2, 3, 4]

# Kontrollwerte aus der Tabelle auf Folie 22
expected_values = {
    (0, 1): 0.00, (0, 2): 0.00, (0, 3): 0.00, (0, 4): 0.00,
    (1, 1): 13.82, (1, 2): 27.64, (1, 3): 41.46, (1, 4): 55.28,
    (2, 1): 39.09, (2, 2): 78.18, (2, 3): 117.27, (2, 4): 156.35,
    (3, 1): 71.81, (3, 2): 143.62, (3, 3): 215.43, (3, 4): 287.24,
    (4, 1): 110.56, (4, 2): 221.12, (4, 3): 331.68, (4, 4): 442.24,
}

# Leere Tabelle erstellen
df_table = pd.DataFrame(
    [[None for _ in n_values] for _ in hü_values],
    columns=[f"n_{n}" for n in n_values],
    index=hü_values
)

df_table.insert(0, "hü", hü_values)

app.layout = html.Div([
    html.Div([
        html.H3("Formel:"),
        html.P("Q = (2/3) ⋅ µ ⋅ b ⋅ √(2 ⋅ g) ⋅ hü^(3/2)", style={'font-size': '18px'}),
        html.P("b = n ⋅ 7.2", style={'font-size': '18px'}),
        html.P("µ = 0.65, g = 9.81", style={'font-size': '18px'}),
    ], style={'margin-bottom': '20px'}),
    
    dash_table.DataTable(
        id='interaktive-tabelle',
        columns=[{"name": "hü", "id": "hü", "editable": False}] + 
                [{"name": f"n = {n}", "id": f"n_{n}", "editable": True} for n in n_values],
        data=df_table.to_dict('records'),
        editable=True,
        style_table={'margin': '20px'},
        style_cell={'textAlign': 'center', 'font-size': '16px'},
        style_header={
            'backgroundColor': 'rgb(220, 220, 220)',
            'fontWeight': 'bold'
        },
        style_data_conditional=[
            {
                'if': {'row_index': 'odd'},
                'backgroundColor': 'rgb(248, 248, 248)'
            }
        ]
    ),
    
    html.Div(id='feedback', style={'margin-top': '20px', 'font-weight': 'bold', 'font-size': '18px'})
])

@app.callback(
    [Output('interaktive-tabelle', 'data'), Output('feedback', 'children')],
    Input('interaktive-tabelle', 'data'),
    State('interaktive-tabelle', 'data_previous')
)
def validate_table(data, data_previous):
    if data_previous is None:
        return data, ""
    
    feedback_messages = []
    
    for row_idx, row in enumerate(data):
        hü_value = row['hü']
        for n in n_values:
            col_name = f"n_{n}"
            prev_value = data_previous[row_idx][col_name] if data_previous else None
            cell_value = row[col_name]
            
            if cell_value is not None and cell_value != prev_value:
                try:
                    cell_value_float = float(cell_value)
                    expected_value = expected_values.get((hü_value, n), None)
                    if expected_value is not None and math.isclose(cell_value_float, expected_value, rel_tol=1e-2):
                        feedback_messages.append(f"✅ Richtig: hü={hü_value}, n={n}: {cell_value_float}")
                        row[col_name] = f"{cell_value_float} ✅"
                    else:
                        feedback_messages.append(f"❌ Falsch: hü={hü_value}, n={n}: {cell_value_float}. Erwartet: {expected_value}")
                        row[col_name] = f"{cell_value_float} ❌"
                except ValueError:
                    feedback_messages.append(f"❌ Ungültige Eingabe: hü={hü_value}, n={n}: {cell_value}")
                    row[col_name] = f"{cell_value} ❌"
    
    return data, "\n".join(feedback_messages)

if __name__ == '__main__':
    app.run(debug=False)
import dash
from dash import dcc, html, Input, Output, State, dash_table
import pandas as pd
import math
import plotly.express as px

# Dash-App erstellen
app = dash.Dash(__name__)

# Formel zur Berechnung von Q
def berechne_Q(hu, n):
    µ = 0.65
    b = n * 7.2
    g = 9.81
    return (2 / 3) * µ * b * math.sqrt(2 * g) * (hu ** (3 / 2))

# Daten definieren
hü_values = [0, 1, 2, 3, 4]
n_values = [1, 2, 3, 4]

# Kontrollwerte aus der Tabelle
expected_values = {
    (hu, n): berechne_Q(hu, n) for hu in hü_values for n in n_values
}

# Leere Tabelle erstellen
df_table = pd.DataFrame(
    [[None for _ in n_values] for _ in hü_values],
    columns=[f"n_{n}" for n in n_values],
    index=hü_values
)
df_table.insert(0, "hü", hü_values)

# Speicherung der bisherigen Werte
previous_plot_data = []

app.layout = html.Div([
    html.Div([
        html.H3("Formel:"),
        html.P("Q = (2/3) ⋅ µ ⋅ b ⋅ √(2 ⋅ g) ⋅ hü^(3/2)", style={'font-size': '18px'}),
        html.P("b = n ⋅ 7.2", style={'font-size': '18px'}),
        html.P("µ = 0.65, g = 9.81", style={'font-size': '18px'}),
    ], style={'margin-bottom': '20px'}),
    
    dash_table.DataTable(
        id='interaktive-tabelle',
        columns=[{"name": "hü", "id": "hü", "editable": False}] + 
                [{"name": f"n = {n}", "id": f"n_{n}", "editable": True} for n in n_values],
        data=df_table.to_dict('records'),
        editable=True,
        style_table={'margin': '20px'},
        style_cell={'textAlign': 'center', 'font-size': '16px'},
        style_header={
            'backgroundColor': 'rgb(220, 220, 220)',
            'fontWeight': 'bold'
        },
        style_data_conditional=[
            {
                'if': {'row_index': 'odd'},
                'backgroundColor': 'rgb(248, 248, 248)'
            }
        ]
    ),
    
    html.Div(id='feedback', style={'margin-top': '20px', 'font-weight': 'bold', 'font-size': '18px'}),
    dcc.Graph(id='plot')
])

@app.callback(
    [Output('interaktive-tabelle', 'data'), Output('feedback', 'children'), Output('plot', 'figure')],
    Input('interaktive-tabelle', 'data'),
    State('interaktive-tabelle', 'data_previous')
)
def validate_table(data, data_previous):
    global previous_plot_data
    if data_previous is None:
        return data, "", px.line()
    
    feedback_messages = []
    new_plot_data = []
    
    for row in data:
        hu_value = row['hü']
        for n in n_values:
            col_name = f"n_{n}"
            cell_value = row[col_name]
            
            if cell_value is not None:
                try:
                    cell_value_float = float(cell_value)
                    expected_value = expected_values.get((hu_value, n), None)
                    if expected_value is not None and math.isclose(cell_value_float, expected_value, rel_tol=1e-2):
                        row[col_name] = f"{cell_value_float} ✅"
                        new_plot_data.append((cell_value_float, hu_value, f"n={n}"))
                    else:
                        row[col_name] = f"{cell_value_float} ❌"
                except ValueError:
                    continue
    
    # Kombiniere alte und neue Werte
    previous_plot_data.extend(new_plot_data)
    df_plot = pd.DataFrame(previous_plot_data, columns=['Q', 'hü', 'n'])
    fig = px.line(df_plot, x='Q', y='hü', color='n', title="Visualisierung der berechneten Q-Werte", markers=True)
    fig.update_layout(yaxis=dict(range=[0, max(hü_values)]), xaxis=dict(range=[0, max(expected_values.values())]))
    
    return data, "\n".join(feedback_messages), fig

if __name__ == '__main__':
    app.run(debug=False)